/*
	Copyright (C) 2009 Salil Bhagurkar
	
	This file is part of ViSE
	
	ViSE is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.
	
	ViSE is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.
	
	You should have received a copy of the GNU Lesser General Public License
	along with ViSE.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _LIST_H_
#define _LIST_H_


/*Doubly linked list management macros *with a tail**/
/*Declare a list as struct whatever *whatever, *whatevertail */

#define list_for(list_head,node) for(node=list_head;node;node=node->next)

/*
..--><--before--><--...
node-->
*/

#define list_destroy(list_head,list_tail) ({\
	typeof(list_head) n,nn;\
	for(n=list_head;n;) {\
		nn=n->next;\
		free(n); \
		n=nn;\
	}\
})


#define list_destroy_and_free(list_head,list_tail) ({\
	typeof(list_head) n,nn;\
	for(n=list_head;n;) {\
		nn=n->next;\
		dlist_detach(list_head,list_tail,n);\
		mm.free(n);\
		n=nn;\
	}\
})


#define list_insert_before(list_head,list_tail,before,node) ({\
	if(!list_head) {\
		list_head=node;\
		list_tail=node;\
		node->next=NULL;\
		node->prev=NULL;\
	} else {\
		if(before->prev)\
			(before->prev)->next=node;\
		node->prev=before->prev;\
		before->prev=node;\
		node->next=before;\
		if(list_head==before)\
			list_head=node;\
	}\
})


#define list_insert_after(list_head,list_tail,after,node) ({\
	if(!list_head) {\
		list_head=node;\
		list_tail=node;\
		node->next=NULL;\
		node->prev=NULL;\
	} else {\
		if(after->next)\
			(after->next)->prev=node;\
		node->next=after->next;\
		after->next=node;\
		node->prev=after;\
		if(list_head==after)\
			list_head=node;\
	}\
})


#define list_attach(list_head,list_tail,node) ({\
	if(!list_tail) {\
		list_head=node;\
		list_tail=node;\
		node->prev=NULL;\
	} else {\
		list_tail->next=node;\
		node->prev=list_tail;\
		list_tail=node;\
	}\
	node->next=NULL;\
})

#define list_detach(list_head,list_tail,node) ({\
	if(list_head==node && list_tail==node)\
		list_head=list_tail=NULL;\
	else {\
		if(!(node->prev)) {\
			list_head=node->next;\
			list_head->prev=NULL;\
		} else if(!(node->next)) {\
			list_tail=node->prev;\
			list_tail->next=NULL;\
		} else {\
			(node->prev)->next=node->next;\
			(node->next)->prev=node->prev;\
		}\
	}\
	node->next = NULL;\
	node->prev = NULL;\
})

#define list_empty(list_head) (list_head)

#define list_present(list_head,node) ( (list_head) && ((node)==(list_head) || (node)->next || (node)->prev) )

#define list_deleted(list_head,node) ( list_head!=node && node->prev == NULL && node->next == NULL)

#define list_init_node(node) node->next = node->prev = NULL

/*Initialize next and prev statically*/
#define LIST_NODE_INIT .next=NULL,.prev=NULL

#endif
